package com.open.rbac.config.security;

import java.util.List;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.open.rbac.model.entity.sys.Role;
import com.open.rbac.model.entity.sys.User;
import com.open.rbac.service.sys.repository.RoleRepository;
import com.open.rbac.service.sys.repository.UserRepository;


/**
 * 自定义认证管理器
 *
 * @author Riche's
 * @since 2022/8/15
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MeUsernamePasswordAuthenticationManager implements AuthenticationProvider {

    private final UserRepository userRepository;

    private final RoleRepository roleRepository;

    private final PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        User user = userRepository.findByUsername(authentication.getPrincipal().toString());
        if (user == null) {
            user = userRepository.findByPhone(authentication.getPrincipal().toString());
        }
        if (user == null) {
            log.error("没有找到账号：{}", authentication.getPrincipal());
            throw new UsernameNotFoundException("账号或密码错误");
        } else if (!passwordEncoder.matches(authentication.getCredentials().toString(), user.getPassword())) {
            log.error("账号：{} 的密码不匹配", user.getUsername());
            throw new BadCredentialsException("用户名或密码错误");
        } else if (Boolean.FALSE.equals(user.getEnable())) {
            log.error("账号：{} 已被禁用", user.getUsername());
            throw new LockedException("账号已被锁定，请联系管理员");
        }
        List<Role> roles = roleRepository.findByUserId(user.getId());
        if (CollectionUtils.isEmpty(roles)) {
            log.error("账号 {}, 没有角色信息", user.getUsername());
            throw new AuthenticationServiceException("没有找到角色信息，请联系管理员");
        }
        MeUsernamePasswordAuthenticationToken token = new MeUsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(),
            roles.stream().map(role -> new SimpleGrantedAuthority(role.getId())).toList());
        token.setId(user.getId());
        token.setAvatar(user.getAvatar());
        token.setUsername(user.getUsername());
        token.setRealName(user.getRealname());
        token.setPassword(user.getPassword());
        token.setEmail(user.getEmail());
        token.setPhone(user.getPhone());
        token.setRoleIds(roles.stream().map(Role::getId).toList());
        return token;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(MeUsernamePasswordAuthenticationToken.class);
    }

}
